#include "store/store.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

struct cache* cache_build(){
	size_t cache_size=sizeof(struct cache);
	struct cache *cc=(struct cache*)malloc(cache_size);
	
	cc->rd_index=0;
	cc->wr_index=0;
	cc->buffer_size=CACHE_BUFFER_COUNT;	
	return cc;
}

int cache_release(struct cache *cc){
	free(cc);
	return 0;
}

int chunk_initial(struct store_chunk *chunk,char *file){
	int rd = open(file,O_RDONLY);
	int wd ;
	if(rd==-1){
		wd=open(file,O_WRONLY|O_APPEND|O_CREAT,S_IRUSR|S_IWUSR);
		rd=open(file,O_RDONLY);
	}else{
		wd=open(file,O_WRONLY|O_APPEND);	
	}
	if(rd==-1){
		chunk->rd_fd=-1;
		chunk->wr_fd=-1;
		return -1;
	}
	off_t length =lseek(wd,0L,SEEK_END);
	size_t size=strlen(file);
	memcpy(chunk->name,file,size);
	chunk->name[size]='\0';
	chunk->rd_fd=rd;
	chunk->wr_fd=wd;
	chunk->wr_index =length;
	chunk->rd_index =0L;
	chunk->cc_rd= cache_build();
	chunk->cc_wr= cache_build();

	struct bufferFactory *hdl = bufferFactory_build(CACHE_BUFFER_SIZE,512);
	if(hdl==NULL){
		return -1;
	}
	chunk->bf_hdl=hdl;
	
	chunk->hashtree=new_htree();
	chunk->hashtree->rd_fd=rd;
    chunk->hashtree->wr_fd=wd;
    chunk->hashtree->wr_index=length;
    chunk->hashtree->rd_index=0L;
	return 0;
}

int chunk_release(struct store_chunk *chunk){
	forc_sync(chunk);
	close(chunk->rd_fd);
	close(chunk->wr_fd);
	cache_release(chunk->cc_rd);
	cache_release(chunk->cc_wr);
	bufferFactory_release(chunk->bf_hdl);
	return 0;
}

void cache_node_release(struct bufferFactory *factory,struct buffer *buff){
	struct buffer *data;
	while(buff){
		data = buff;
		buffer_del(factory,data);
		buff = buff->next;
	}
}

/**
 * stream style
 **/
int forc_sync(struct store_chunk *chunk){
	struct cache *cc=chunk->cc_wr;
	int i=cc->rd_index;
	int bound=cc->wr_index;
	int ret=0;
	for(;i<bound;i++){
		struct buffer *data=(cc->data_arr)[i];
		struct buffer *prelease=data;

		while(data){/**同步一个缓冲链表*/
			ret=write_data(chunk,data);
			//TODO if(ret == -1)
			data=data->next;
		}
		cache_node_release(chunk->bf_hdl,prelease);
	}
	cc->rd_index=0;
	cc->wr_index=0;
	return ret;
}

int save_key(struct buffer *buff_in,void *key,size_t key_len,struct store_chunk *chunk){
	return save(chunk->hashtree,key,key_len,buff_in);
}

int query_key(struct buffer *buff_out,void *key,size_t key_len,struct store_chunk *chunk){
	return find(chunk->hashtree,key,key_len,buff_out);
}

int take_key(struct buffer *buff_out,void *key,size_t key_len,struct store_chunk *chunk){
	return take(chunk->hashtree,key,key_len);
}

/**
 * 设立两个缓冲区。
 * app->wr_buff->disk
 * disk->rd_buff->app
 * wr_buff写满之后，写到磁盘。rd_buff读完之后，从磁盘读取。如果磁盘文件也到了末尾，立刻
 * 将wr_buff的数据转移到rd_buff上。
 **/

int save_stream(struct buffer *buff_in,struct store_chunk *chunk){
	struct cache *cc=chunk->cc_wr;
	if(cc->wr_index == cc->buffer_size){
		forc_sync(chunk);
	}	
	if(cc->wr_index < CACHE_BUFFER_COUNT){
		(cc->data_arr)[cc->wr_index]=buff_in;
		cc->wr_index +=1;
		return 0;
	}
	return 1;
}

int query_stream(struct buffer **buff_out,struct store_chunk *chunk){
	struct cache *cc=chunk->cc_rd;
	if(cc->rd_index == 0||cc->rd_index == cc->buffer_size){/**读缓存没有内容，或者之前读完了*/
		cc->rd_index=0;
		cc->wr_index=0;

		int i=0;
		int ret=0;
		for(;i< cc->buffer_size;i++){
			/**头的长度在此保留，在这里检查每次buffer读入的数量，不断分配，链表接**/
			short len=0;
			
			struct buffer *buff=buffer_new(chunk->bf_hdl);
			ready_to_read(buff);
			ret=read_data(chunk,buff,1);/**读了一个数据单元的头*/
			if(ret){/**如果发生了错误，释放分配的buffer*/
				cache_node_release(chunk->bf_hdl,buff);
				break;
			}
			
			ready_to_write(buff);/**将读到的头分析一下*/
			short value;
			int is_big = is_big_cpu();
			bytes_to_short(buff,&value,is_big);/**按cpu字节序重组*/
			len=value;
			
			/**因为一个数据单元可能超过一个buffer的长度，所以buffer是一个链表*/
			struct buffer *head=buff;/**链表头，读缓存将存储这个值*/
			struct buffer *tail=buff;/**链表尾，读取文件过程中这个值变化，并形成链表*/
			while(1){
				ready_to_read(buff);
				if(value < buff->length){/**如果剩余的数据长度小于buffer的大小，要调整buffer的limit*/
					buff->limit=value;
				}/**否则buffer的limit尽最大可能的装载*/
				
				ret=read_data(chunk,buff,0);
				if(ret){/**如果出错，全部释放分配的buffer*/
					cache_node_release(chunk->bf_hdl,head);
					return 1;
				}
				len = len - buff->index;/**剩余的数据长度 = 原来的剩余数 - 这次读取的数*/
				if(len == 0){/**如果剩余为0，说明数据单元已经读完了*/
					(cc->data_arr)[i]=head;/**链表存入缓存，缓存的写指针前移一位*/
					cc->wr_index +=1;
					break;
				}
				/**数据单元没有读完，分配新的buffer，接到尾巴上，新的buffer变成尾巴*/
				buff=buffer_new(chunk->bf_hdl);
				tail->next=buff;
				tail=buff;
			}
		}
	}
	
	if(cc->wr_index==0){/**从文件中也没有读到内容*/
		struct cache *cc_w=chunk->cc_wr;
		int i=cc_w->rd_index;
		for(;i<cc_w->wr_index;i++){
			(cc->data_arr)[cc->wr_index]=(cc_w->data_arr)[i];
			cc->wr_index +=1;
		}
		cc_w->rd_index=0;
		cc_w->wr_index=0;
	}
	
	if(cc->wr_index==0){/**从写缓存中也没有读到内容*/
		return 1;
	}
	(*buff_out)=(cc->data_arr)[cc->rd_index];
	cc->rd_index +=1;
	return 0;
}

